#include<stdio.h>
#include<string.h>
#include"WorldMap.h"


bool WorldMap::LoadLevel(char *filename)
{
   Q3Header Header;
   Q3FileLump Lumps[iMaxLumpsOffset];

   // Open file.
   FILE *fp = fopen(filename, "rb");
   if(!fp) return false;

   // Read the header data and make sure this is a bsp level.
   fread(&Header, 1, sizeof(Q3Header), fp);
   if(strcmp(Header.bspID, "IBSP.") != 0) return false;

   // Read all the lumps in the file.
	fread(&Lumps, iMaxLumpsOffset, sizeof(Q3FileLump), fp);

   // Allocate data for the vertex points, triangles, textures, and lightmaps.
   m_totalVertices = Lumps[iVerticesOffset].length / sizeof(Q3Vertex);
	m_vertices = new Q3Vertex[m_totalVertices];

   m_totalFaces = Lumps[iFacesOffset].length / sizeof(Q3Face);
	m_faces = new Q3Face[m_totalFaces];

   m_totalTextures = Lumps[iTextureOffset].length / sizeof(Q3Texture);
   m_textures = new Q3Texture[m_totalTextures];

   m_totalLightMaps = Lumps[iLightMapsOffset].length / sizeof(Q3LightMap);
   m_lightMaps = new Q3LightMap[m_totalLightMaps];

   // Load the vertex data.
	fseek(fp, Lumps[iVerticesOffset].offset, SEEK_SET);
	fread(m_vertices, m_totalVertices, sizeof(Q3Vertex), fp);

   // Load the triangle data.
   fseek(fp, Lumps[iFacesOffset].offset, SEEK_SET);
	fread(m_faces, m_totalFaces, sizeof(Q3Face), fp);

   // Load the texture data.
	fseek(fp, Lumps[iTextureOffset].offset, SEEK_SET);
	fread(m_textures, m_totalTextures, sizeof(Q3Texture), fp);

   // Load the lightmap data.
	fseek(fp, Lumps[iLightMapsOffset].offset, SEEK_SET);
	fread(m_lightMaps, m_totalLightMaps, sizeof(Q3LightMap), fp);

   fclose(fp);

   return true;
}
bool WorldMap::initWorldMap()
{
   // Load the .bsp level.
   if(!LoadLevel("ugpTestMap.bsp")) return false;
   SwapAxis();

   dxMgr.Texture = new LPDIRECT3DTEXTURE9[m_totalTextures];
   dxMgr.LightMaps = new LPDIRECT3DTEXTURE9[m_totalLightMaps];

   // Load the textures we will need.
   for(int i = 0; i < m_totalTextures; i++) 
	   {
	      if(strcmp("noshader", m_textures[i].file) == 0) continue;
         strcat(m_textures[i].file, ".tga");

         // Here we load the texture into the texture object.
         if(D3DXCreateTextureFromFile(dxMgr.getDevice(), m_textures[i].file,
            &dxMgr.Texture[i]) != D3D_OK) return false;
	   }

	// Load the lightmaps we will need.
   for(int i = 0; i < m_totalLightMaps; i++) 
	   {
	     // ApplyGamma(&BspLevel.m_lightMaps[i].lightMap[0][0][0],
	               //  128 * 128 * 3, 3, 10);

         if(FAILED(D3DXCreateTexture(dxMgr.getDevice(), 128, 128, 1, 0, 
             D3DFMT_R8G8B8, D3DPOOL_MANAGED, &dxMgr.LightMaps[i]))) return false;

         D3DLOCKED_RECT lr;
         dxMgr.LightMaps[i]->LockRect(0, &lr, NULL, 0);

         DWORD *tempImg = (DWORD*)lr.pBits;
         if(!tempImg) continue;
         int index = 0;
         for(int k = 0; k < 128; k++)
            {
               for(int j = 0; j < 128; j++)
                  {
                     tempImg[index++] = (m_lightMaps[i].lightMap[j][k][0] << 16) |
                        (m_lightMaps[i].lightMap[j][k][1] << 8) |
                        m_lightMaps[i].lightMap[j][k][2];
                  }
            }

         dxMgr.LightMaps[i]->UnlockRect(0);
	   }

   // Create the vertex buffer that will hold the square.
	if(FAILED(dxMgr.getDevice()->CreateVertexBuffer(sizeof(Q3Vertex) *
	  m_totalVertices, 0, 0, D3DPOOL_DEFAULT, &dxMgr.Vertex_Buffer, NULL)))
      return false;

   // Pointer to the buffer.
   Q3Vertex* Vertices;

   // Lock the buffer we can write to it.
   if(FAILED(dxMgr.Vertex_Buffer->Lock(0, sizeof(Q3Vertex) *
      m_totalVertices, (void**)&Vertices, 0))) return false;

   // Here we copy the square's data into the vertex buffer.
   memcpy(Vertices, m_vertices, sizeof(Q3Vertex) * m_totalVertices);
   dxMgr.Vertex_Buffer->Unlock();

   // Set description.
   D3DVERTEXELEMENT9 Declaration[] = 
	   {
	      {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
		   {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
		   {0, 20, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
		   {0, 28, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
		   {0, 40, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
		   D3DDECL_END()
	   };

   dxMgr.getDevice()->CreateVertexDeclaration(Declaration, &dxMgr.VertexDeclaration);

   return true;
}

void WorldMap::SwapAxis()
{
   // Must swap the axis for OpenGL.
   for(int i = 0; i < m_totalVertices; i++)
	   {
		   float temp = m_vertices[i].vertex.y;
		   m_vertices[i].vertex.y = m_vertices[i].vertex.z;
		   m_vertices[i].vertex.z = -temp;

		   m_vertices[i].texCoord.tv *= -1;
	   }
}

void WorldMap::Render()
{
	for(int i = 0; i < m_totalFaces; i++)
         {
            if(m_faces[i].type != 1) continue;
            Q3Face *pFace = &m_faces[i];

		      // Set texture image.
            dxMgr.getDevice()->SetTexture(0, dxMgr.Texture[pFace->texID]);
            dxMgr.getDevice()->SetTexture(1, dxMgr.LightMaps[pFace->lightmapID]);

            // Set up data stream.
            dxMgr.getDevice()->SetVertexDeclaration(dxMgr.VertexDeclaration);
            dxMgr.getDevice()->SetStreamSource(0, dxMgr.Vertex_Buffer, 0, sizeof(Q3Vertex));

            // Draw.
            dxMgr.getDevice()->DrawPrimitive(D3DPT_TRIANGLEFAN, pFace->startVertexIndex,
                                     pFace->totalVertices / 2);
         }
}
void WorldMap::Shutdown()
{
   if(m_lightMaps)
      {
         delete[] m_lightMaps;
         m_lightMaps = NULL;
      }

   if(m_textures)
      {
         delete[] m_textures;
         m_textures = NULL;
      }

   if(m_vertices)
      {
         delete[] m_vertices;
         m_vertices = NULL;
      }

   if(m_faces)
      {
         delete[] m_faces;
         m_faces = NULL;
      }

   m_totalLightMaps = 0;
   m_totalTextures = 0;
   m_totalVertices = 0;
   m_totalFaces = 0;
}